package il.ac.tau.cg.ex5.obj.parser;

import il.ac.tau.cg.ex5.obj.ObjEntity;
import il.ac.tau.cg.ex5.util.Color;
import il.ac.tau.cg.ex5.util.Face;
import il.ac.tau.cg.ex5.util.Vertex;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ObjParser
{
	public ObjEntity parse(File file) throws IOException
	{
		List<Vertex> vertexList = new ArrayList<Vertex>();
		List<Vertex> normalList = new ArrayList<Vertex>();
		List<Face> faceList = new ArrayList<Face>();
		
		BufferedReader reader = new BufferedReader(new FileReader(file));
		String line = null;
		
		while ((line = reader.readLine()) != null)
		{
			String[] parts = line.trim().split("[\\s]+");
			
			if ((parts.length == 0) || ((parts.length == 1) && (parts[0].length() == 0)))
			{
				continue;
			}
			
			String prefix = parts[0];
			
			if (prefix.equals(LineTypes.LINE_COMMENT_PREFIX) ||
				prefix.equals(LineTypes.LINE_GROUP_NAME_PREFIX) ||
				prefix.equals(LineTypes.LINE_OBJECT_NAME_PREFIX) ||
				prefix.equals(LineTypes.LINE_TEXTURE_VERTEX_PREFIX) ||
				prefix.equals(LineTypes.LINE_SMOOTH_SHADING_PREFIX) ||
				prefix.equals(LineTypes.LINE_MATERIAL_LIB_PREFIX) ||
				prefix.equals(LineTypes.LINE_USE_MATREIAL_PREFIX))
			{
				continue;
			}
			
			if (prefix.equals(LineTypes.LINE_NORMAL_VECTOR_PREFIX))
			{
				float x = Float.parseFloat(parts[1]);
				float y = Float.parseFloat(parts[2]);
				float z = Float.parseFloat(parts[3]);
				
				normalList.add(new Vertex(x, y, z));
				
				continue;
			}
			
			if (prefix.equals(LineTypes.LINE_VERTEX_PREFIX))
			{
				float x = Float.parseFloat(parts[1]);
				float y = Float.parseFloat(parts[2]);
				float z = Float.parseFloat(parts[3]);
				
				vertexList.add(new Vertex(x, y, z));
				
				continue;
			}
			
			if (prefix.equals(LineTypes.LINE_FACE_PREFIX))
			{
				if (parts.length > 5)
				{
					System.out.println("*** Non-triangle and non-quad face encountered: " + line);
				}
				
				if (parts.length == 4)
				{
					parts = Arrays.copyOf(parts, 5);
					parts[4] = parts[3];
				}
				
				Vertex[] vertices = new Vertex[4];
				Vertex[] normals = null;
				Color[] colors = new Color[4];
				
				for (int i = 1; i < parts.length; i++)
				{
					String part = parts[i];
					String[] faceParts = part.split("/");
					
					for (int j = 0; j < faceParts.length; j++)
					{
						switch (j)
						{
							case 0:
							{
								int vertexIndex = Integer.parseInt(faceParts[0]);
								
								if (vertexIndex < 0)
								{
									vertexIndex += vertexList.size() + 1;
								}
								
								Vertex vertex = vertexList.get(vertexIndex - 1);
								
								vertices[i - 1] = vertex;
							}
							break;
							
							case 2:
							{
								if (normals == null)
								{
									normals = new Vertex[4];
								}
								
								int normalIndex = Integer.parseInt(faceParts[2]);
								
								if (normalIndex < 0)
								{
									normalIndex += normalList.size() + 1;
								}
								
								Vertex normal = normalList.get(normalIndex - 1);
								
								normals[i - 1] = normal;
							}
							break;
						}
					}
					
					colors[i - 1] = new Color(0.8f, 1.0f, 0.4f);
				}
				
				if (normals == null)
				{
					normals = new Vertex[4];
					
					Vertex v1 = vertices[2].subtract(vertices[1]);
					Vertex v2 = vertices[0].subtract(vertices[1]);
					Vertex n = v1.cross(v2);
					
					normals[0] = n;
					normals[1] = n;
					normals[2] = n;
					normals[3] = n;
				}
				
				faceList.add(new Face(vertices, normals, colors));
				
				continue;
			}
			
			System.out.println("*** Unidentified prefix: " + line);
		}
		
		Face[] faces = new Face[faceList.size()];
		
		for (int i = 0; i < faceList.size(); i++)
		{
			faces[i] = faceList.get(i);
		}
		
		return new ObjEntity(faces);
	}
}
